package fr.ul.ade.prime.ui;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.CursorAdapter;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;

import com.actionbarsherlock.view.ActionMode;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.Window;

import fr.ul.ade.R;
import fr.ul.ade.prime.model.AdeWebOptions;
import fr.ul.ade.prime.model.Schedule;
import fr.ul.ade.prime.model.ScheduleState;
import fr.ul.ade.prime.service.AdeWebNotificationManager;

public class ScheduleList extends AdeWebFragmentActivity implements
		BundleExtraNames {

	@SuppressWarnings("hiding")
	protected static final String TAG = ScheduleList.class.getSimpleName();

	protected static final int PROGRESS_UPDATE_DELAY = 10; /* en ms */

	private static final int REFRESH_ID = 1;

	protected String scheduleName;

	protected Schedule displayedSchedule;

	protected ActionMode mActionMode;

	protected ScheduleListAdapter adapter;

	protected boolean actionModeEnabled;

	protected Handler handler;

	protected ProgressUpdateRunnable updateProgressBar = new ProgressUpdateRunnable();

	protected boolean themeChanged;

	// -----------

	protected long displayedScheduleId;

	protected String displayedScheduleName;

	protected ScheduleState displayedScheduleState;

	public void setDisplayedScheduleId(long displayedScheduleId) {
		this.displayedScheduleId = displayedScheduleId;
	}

	public long getDisplayedScheduleId() {
		return this.displayedScheduleId;
	}

	public String getDisplayedScheduleName() {
		return this.displayedScheduleName;
	}

	public Schedule getDisplayedSchedule() {
		return this.displayedSchedule;
	}

	public void setDisplayedSchedule(Schedule displayedSchedule) {
		this.displayedSchedule = displayedSchedule;
	}

	public void setDisplayedScheduleName(String displayedScheduleName) {
		this.displayedScheduleName = displayedScheduleName;
	}

	public ScheduleState getDisplayedScheduleState() {
		return this.displayedScheduleState;
	}

	public void setDisplayedScheduleState(ScheduleState displayedScheduleState) {
		this.displayedScheduleState = displayedScheduleState;
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		this.setTheme(AdeWebOptions.getThemeAde(this));
		AdeWebNotificationManager
				.removeNotificationForImportantScheduleChange(this,
						AdeWebNotificationManager.SCHEDULE_NOTIFICATION_TAG);

		// This has to be called before setContentView
		this.requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
		this.requestWindowFeature(Window.FEATURE_PROGRESS);
		this.setSupportProgressBarIndeterminateVisibility(false);
		this.setSupportProgressBarVisibility(false);

		this.getSupportActionBar().setSubtitle(R.string.ScheduleList_label);
		this.setContentView(R.layout.schedule_list);

		// XXX Temporary
		View bdd = this.findViewById(R.id.bdd);
		final ScheduleList act = this;
		bdd.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Intent intent = new Intent(act, Bdd.class);
				act.startActivity(intent);
			}
		});
		// ---------------
		this.handler = new Handler();
		this.themeChanged = false;

		// Hide schedule details and list fragment
		FragmentManager fm = this.getSupportFragmentManager();
		ScheduleDetailsFragment detailsFragment = (ScheduleDetailsFragment) fm
				.findFragmentById(R.id.schedule_details);
		Fragment listFragment = fm.findFragmentById(R.id.schedule_list);
		FragmentTransaction ft = fm.beginTransaction();
		if (!detailsFragment.isHidden()) {
			ft.hide(detailsFragment);
		}// if
		if (listFragment.isHidden()) {
			ft.show(listFragment);
		}// if
		ft.commit();
	}// onCreate(Bundle)

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onResume() {
		super.onResume();
		// Log.d(TAG, "[onStart] themeChanged: " + this.themeChanged) ;
		if (this.themeChanged) {
			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
				this.recreate();
			} else {
				this.startActivity(new Intent(this, ScheduleList.class));
				this.finish();
			}// if
		}// if
	}// onResume()

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		Intent createScheduleIntent = new Intent(this, CreateSchedule.class);
		Intent userManualIntent = new Intent(this, UserManual.class);
		Intent preferencesIntent = new Intent(this, Preference.class);

		if (!this.updateProgressBar.isRunning()) {
			this.setSupportProgressBarIndeterminateVisibility(false);
			this.setSupportProgressBarVisibility(false);
			menu.add(Menu.NONE,
					REFRESH_ID,
					Menu.NONE,
					R.string.ActionBar_refresh)
					.setIcon(R.drawable.ic_action_refresh_holo_dark)
					.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
		}// if

		menu.add(R.string.ActionBar_add)
				.setIcon(R.drawable.ic_action_new_holo_dark)
				.setIntent(createScheduleIntent)
				.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);

		menu.add(R.string.ActionBar_preferences)
				.setIcon(R.drawable.ic_action_settings_holo_light)
				.setIntent(preferencesIntent)
				.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);

		menu.add(R.string.ActionBar_help)
				.setIcon(R.drawable.ic_action_help_holo_light)
				.setIntent(userManualIntent)
				.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);

		return super.onCreateOptionsMenu(menu);
	}// onCreateOptionsMenu(Menu)

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		if (item.getItemId() == REFRESH_ID) {
			if (AdeWebOptions.networkIsAvailable(this)) {
				ScheduleListFragment fragment = (ScheduleListFragment) this
						.getSupportFragmentManager()
						.findFragmentById(R.id.schedule_list);
				fragment.updateSchedule();
			} else {// No network is available, no need to try updating
				Toast.makeText(this,
						R.string.Sync_no_network,
						Toast.LENGTH_SHORT).show();
			}// if
			return true;
		}// if

		return false;
	}// onOptionsItemSelected(MenuItem)

	public static final class ScheduleActionMode implements ActionMode.Callback {

		protected static final int MODIFY_ID = 0;

		protected static final int UPDATE_ID = 1;

		protected static final int DELETE_ID = 2;

		protected static final int HELP_ID = 3;

		private ScheduleList activity;

		public ScheduleActionMode(ScheduleList activity) {
			super();
			this.activity = activity;
		}// ScheduleActionMode(ScheduleList)

		@Override
		public boolean onCreateActionMode(ActionMode mode, Menu menu) {
			menu.add(Menu.NONE, MODIFY_ID, Menu.NONE, R.string.ActionBar_modify)
					.setIcon(R.drawable.ic_action_edit_holo_dark)
					.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);

			menu.add(Menu.NONE,
					UPDATE_ID,
					Menu.NONE,
					R.string.ActionBar_refresh)
					.setIcon(R.drawable.ic_action_refresh_holo_dark)
					.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);

			menu.add(Menu.NONE, DELETE_ID, Menu.NONE, R.string.ActionBar_delete)
					.setIcon(R.drawable.ic_action_discard_holo_dark)
					.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);

			menu.add(Menu.NONE, HELP_ID, Menu.NONE, R.string.ActionBar_help)
					.setIcon(R.drawable.ic_action_help_holo_light)
					.setIntent(new Intent(this.activity, UserManual.class))
					.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);

			return true;
		}// onCreateActionMode(ActionMode, Menu)

		@Override
		public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
			return true;
		}// onPrepareActionMode(ActionMode, Menu)

		@Override
		public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
			int itemId = item.getItemId();
			boolean consumeEvent = true;
			if (itemId == HELP_ID) {
				consumeEvent = false;
			} else if (itemId == UPDATE_ID) {
				ScheduleState state = this.activity.displayedScheduleState;
				consumeEvent = !state.isUpdating();
				if (consumeEvent) {
					if (AdeWebOptions.networkIsAvailable(this.activity)) {
						this.activity.service
								.launchScheduleUpdate(this.activity.displayedScheduleId);
					} else {
						Toast.makeText(this.activity,
								R.string.Sync_no_network,
								Toast.LENGTH_SHORT).show();
					}// if
				}// if
			} else {
				ScheduleState state = this.activity.displayedScheduleState;
				if (state.equals(ScheduleState.OTHER)
						|| state.equals(ScheduleState.UPDATED)
						|| state.equals(ScheduleState.NOT_UPDATED)) {
					switch (itemId) {
					case MODIFY_ID:
						Intent editScheduleIntent = new Intent(this.activity,
								EditSchedule.class);
						editScheduleIntent.putExtra(EXTRA_SCHEDULE_ID,
								this.activity.displayedScheduleId);
						this.activity.startActivity(editScheduleIntent);
						break;

					case DELETE_ID:
						this.activity.deleteSchedule();
						break;
					default:
					}// switch
				} else {
					Toast.makeText(this.activity,
							R.string.ScheduleList_action_not_available,
							Toast.LENGTH_SHORT).show();
				}// if
			}// if
			return consumeEvent;
		}// onActionItemClicked(ActionMode, MenuItem)

		@Override
		public void onDestroyActionMode(ActionMode mode) {
			FragmentManager fm = this.activity.getSupportFragmentManager();
			Fragment detailsFragment = fm
					.findFragmentById(R.id.schedule_details);
			Fragment listFragment = fm.findFragmentById(R.id.schedule_list);
			FragmentTransaction ft = fm.beginTransaction();
			ft.setCustomAnimations(android.R.anim.fade_in,
					android.R.anim.fade_out);

			if (!detailsFragment.isHidden()) {
				ft.hide(detailsFragment);
				ft.show(listFragment);
			}// if
			ft.commit();

			this.activity.displayedScheduleId = 0L;
			this.activity = null;
		}// onDestroyActionMode(ActionMode)

	}// class ScheduleActionMode

	public void updateActionModeState() {
		// Log.d(TAG, "[updateActionModeState]") ;
		if (this.displayedScheduleId > 0) {
			// Log.d(TAG, "-- this.displayedSchedule not null =)") ;
			ScheduleState state = this.displayedScheduleState;
			this.actionModeEnabled = !state.isUpdating();
			if (this.mActionMode != null) {
				// Log.d(TAG, "-- this.mActionMode not null =)") ;
				// Log.d(TAG, "-- state: " + state) ;
				MenuItem item = this.mActionMode.getMenu()
						.getItem(ScheduleActionMode.UPDATE_ID);
				if (state.equals(ScheduleState.WAITING_FOR_UPDATE)) {
					item.setIcon(R.drawable.cancel);
				} else if ((state.isUpdating()
						|| state.equals(ScheduleState.UPDATED) || state
							.equals(ScheduleState.NOT_UPDATED))) {
					item.setIcon(R.drawable.ic_action_refresh_holo_dark);
				}// if
			}// if
		}// if
	}// updateActionModeState()

	protected void deleteSchedule() {
		final ScheduleList activity = this;
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		String name = this.displayedScheduleName;
		String message = this.getResources()
				.getString(R.string.Schedule_delete_confirm_text);
		builder.setMessage(String.format(message, name))
				.setTitle(R.string.Schedule_delete_title);
		builder.setIcon(RESULT_OK);

		// Valider la suppression
		builder.setPositiveButton(R.string.Yes,
				new DialogInterface.OnClickListener() {
					// Supression de l'edt
					@Override
					public void onClick(DialogInterface dialog, int which) {
						activity.service
								.removeSchedule(activity.displayedScheduleId);
						activity.mActionMode.finish();
					}// onClick(DialogInterface, int)
				});

		// Annuler la suppression
		builder.setNegativeButton(R.string.Cancel,
				new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}// onClick(DialogInterface, int)
				});
		Dialog dialog = builder.create();
		dialog.show();
	}// deleteSchedule()

	public void updateProgressBar(CursorAdapter cursorAdapter) {
		int max = 0, nUpdatingSchedules = 0, nSchedules = cursorAdapter
				.getCount();
		for (int s = 0; s < nSchedules; ++s) {
			Cursor cursor = (Cursor) cursorAdapter.getItem(s);
			ScheduleState state = ScheduleState.getState(cursor
					.getInt(ScheduleListFragment.ScheduleQuery.SCHEDULE_STATE));
			max += state.getWeight();
			switch (state) {
			default:
				nUpdatingSchedules++;
				//$FALL-THROUGH$
			case OTHER:
			case UPDATED:
			case NOT_UPDATED:
			}// switch
		}// while
		this.updateProgressBar.setCurrentMax(max,
				nUpdatingSchedules,
				nSchedules);
	}// updateProgressBar(Cursor)

	private class ProgressUpdateRunnable implements Runnable {

		private final int DEFAULT_STEP = 2;

		private final int FAST_STEP = 10;

		private int step;

		private boolean running;

		protected int nSchedules;

		protected int currentMax;

		protected int currentProgress;

		protected ProgressUpdateRunnable() {
			super();
			this.currentProgress = 100;
			this.currentMax = 0;
			this.step = this.DEFAULT_STEP;
			this.running = false;
		}// ProgressUpdateRunnable()

		@Override
		public void run() {
			final ScheduleList sl = ScheduleList.this;
			if (this.currentProgress < this.currentMax) {
				this.currentProgress += this.step;
				int scale = (android.view.Window.PROGRESS_END - android.view.Window.PROGRESS_START) / 100;
				sl.setSupportProgress(this.currentProgress * scale
						/ this.nSchedules);
			}// if
			if (this.currentProgress < 100 * this.nSchedules) {
				sl.handler.postDelayed(this, PROGRESS_UPDATE_DELAY);
			} else {
				// Log.d(TAG, ">> 100% reached !");
				sl.setSupportProgressBarVisibility(false);
				sl.setSupportProgressBarIndeterminateVisibility(false);
				sl.handler.postDelayed(new Runnable() {
					@Override
					public void run() {
						sl.invalidateOptionsMenu();
					}// run
				}, PROGRESS_UPDATE_DELAY);
				this.running = false;
			}// if
		}// run()

		public void setCurrentMax(int currentMax, int nUpdatingSchedules,
				int nSchedules) {
			// Log.d(TAG, String.format("max,nS: %3d/%3d|%2d --> %3d/%3d|%2d",
			// this.currentProgress, this.currentMax, this.nSchedules,
			// this.currentProgress, currentMax, nSchedules));
			if (nSchedules == 0) {
				this.currentProgress = 100;
			} else if (currentMax > 0) {
				if (!this.running && (nUpdatingSchedules > 0)) {
					this.running = true;
					final ScheduleList sl = ScheduleList.this;
					sl.invalidateOptionsMenu();
					sl.setSupportProgressBarIndeterminateVisibility(true);
					this.currentProgress = 0;
					this.step = this.DEFAULT_STEP;
					sl.handler.post(this);
				} else if (this.running && (nUpdatingSchedules == 0)) {
					this.step = FAST_STEP;
				}// if
				this.currentMax = currentMax;
				this.nSchedules = nSchedules;
			}// if
		}// setCurrentMax(int, int)

		public boolean isRunning() {
			return this.running;
		}// isRunning()

	}// class ProgressUpdateRunnable

}// class ScheduleList